package com.aura.common.redis.service;

import com.aura.common.core.utils.JsonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @ClassName RedisListService
 * @Description
 * @Author ZJX
 * @Date 2025/7/19 23:53
 * @Version 1.0
 **/
@Component
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class RedisListService {
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 缓存List数据  插⼊整个list数据，并保持原顺序
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 添加元素后 Redis 列表的长度
     * @param <T> 对象类型
     */
    public <T> Long setCacheList(final String key, final List<T> dataList){
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }

    /**
     * 从List结构左侧插入数据（头插、入队）
     * @param key key
     * @param value 缓存的对象
     * @param <T> 值类型
     */
    public <T> void leftPushForList(final String key, final T value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 从List结构右侧插入数据（尾插、插入单个数据）
     * @param key key
     * @param value 缓存的对象
     * @param <T> 值类型
     */
    public <T> void rightPushForList(final String key, final T value) {
        redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 删除左侧第一个数据 （头删）
     * @param key   key
     */
    public void leftPopForList(final String key){
        redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 删除右侧第一个数据 （尾删）
     * @param key   key
     */
    public void rightPopForList(final String key) {
        redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移除List第一个匹配的元素
     * 说明：
     *  * - 对应 Redis 的 LREM 命令；
     *  * - count = 1：从左往右删除第一个匹配项；
     *  * - 删除方向说明：
     *  *    count > 0：左 → 右；   count < 0：右→左；  count = 0：全部删除；
     * @param key key
     * @param value 值
     * @param <T> 值类型
     */
    public <T> void removeForList(final String key, T value){
        //删除的方向： count > 0 从左往右   <0 从右往左  == 0 全部删除
        redisTemplate.opsForList().remove(key,1L,value);
    }


    /**
     * 移除List中匹配的所有列表元素
     *
     * @param key key
     * @param value 值
     * @param <T> 值类型
     */
    public <T> void removeAllForList(final String key, T value) {
        redisTemplate.opsForList().remove(key, 0, value);
    }

    /**
     * 清空指定列表中的所有元素（通过 Redis LTRIM 实现）
     * 使用场景：
     * 1. 保留最近 N 条记录： trim(key, -N, -1)  → 只保留最后 N 个元素
     * 2. 清空整个列表     ： trim(key, -1, 0)   → 范围非法，清空整个列表
     * 3. 截断老旧数据     ： trim(key, 0, 4)    → 只保留前 5 个元素
     *
     * @param key Redis 列表 key
     */
    public void removeForAllList(final String key) {
        redisTemplate.opsForList().trim(key, -1, 0);
    }


    /**
     *  修改指定下标数据
     * @param key        key
     * @param index     下标
     * @param newValue  修改后新值
     * @param <T>       值类型
     */
    public <T> void setElementAtIndex(final String key, int index, T newValue){
        redisTemplate.opsForList().set(key,index,newValue);
    }

    /**
     * 获得缓存的list对象
     * @param key key 缓存的键值
     * @param clazz 对象的类
     * @return 列表
     * @param <T> 对象类型
     */
    public <T> List<T> getCacheList(final String key, Class<T> clazz){
        //  0 代表第一个元素  1 ：第二个元素  2 第三个元素 依次类推
        // -1 最后一个元素  -2 倒数第二个元素  依次类推
        List list = redisTemplate.opsForList().range(key, 0, -1);
        return JsonUtil.string2List(JsonUtil.obj2String(list),clazz);
    }

    /**
     * 获得缓存的list对象 （支持复杂的泛型嵌套）
     * @param key key信息
     * @param typeReference 类型模板
     * @return list对象
     * @param <T> 对象类型
     */
    public <T> List<T> getCacheList(final String key, TypeReference<List<T>> typeReference){
        List list = redisTemplate.opsForList().range(key, 0, -1);
        List<T> ret = JsonUtil.string2Obj(JsonUtil.obj2String(list), typeReference);
        return ret;
    }

    /**
     * 根据范围获取List
     *
     * @param key key
     * @param start 开始位置
     * @param end 结束位置
     * @param clazz 类信息
     * @return List列表
     * @param <T> 类型
     */
    public <T> List<T> getCacheListByRange(final String key, long start, long end, Class<T> clazz){
        List list = redisTemplate.opsForList().range(key, start, end);
        return JsonUtil.string2List(JsonUtil.obj2String(list),clazz);
    }


    /**
     * 根据范围获取List（支持复杂的泛型嵌套 ）
     *
     * @param key key
     * @param start 开始
     * @param end 结果
     * @param typeReference 类型模板
     * @return list列表
     * @param <T> 类型信息
     */
    public <T> List<T> getCacheListByRange(final String key, long start, long end, TypeReference<List<T>> typeReference) {
        List list = redisTemplate.opsForList().range(key, start, end);
        return JsonUtil.string2Obj(JsonUtil.obj2String(list),typeReference);
    }


    /**
     * 获取指定列表长度
     * @param key key信息
     * @return 列表长度
     */
    public long getCacheListSize(final String key) {
        Long size = redisTemplate.opsForList().size(key);
        return size == null ? 0L : size;
    }

    /**
     * 获取指定索引位置的元素
     *
     * @param key Redis 列表的 key
     * @param index 索引位置（支持负数：-1 表示最后一个）
     * @param clazz 反序列化所需的目标类型
     * @return 指定位置的元素对象，若不存在返回 null
     * @param <T> 对象类型
     */
    public <T> T getElementAtIndex(final String key, long index, Class<T> clazz) {
        Object object = redisTemplate.opsForList().index(key, index);
        return JsonUtil.string2Obj(JsonUtil.obj2String(object),clazz);
    }

    /**
     * 只保留列表中的最后 N 个元素，删除其他元素
     * 使用场景：
     * - 控制队列长度，避免列表无限增长；
     * - 保留最近 N 条操作、消息、日志等记录；
     * 示例：
     * - count = 100 → 保留最后 100 个元素；
     * - 实现效果：trim(key, -100, -1)
     *
     * @param key Redis 列表 key
     * @param count 要保留的元素数量（从列表尾部向前数）
     */
    public void keepLastNElements(final String key, int count) {
        redisTemplate.opsForList().trim(key,-count,-1);
    }


}